package se.webbzon.boltzmann.game;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;

import se.webbzon.boltzmann.environment.VariableEntry;
import se.webbzon.boltzmann.game.environment.GameEnvironment;
import se.webbzon.boltzmann.game.region.RegionObject;
import se.webbzon.boltzmann.inventory.Inventory;
import se.webbzon.boltzmann.item.AbstractItem;
import se.webbzon.boltzmann.player.CharacterEnum;
import se.webbzon.boltzmann.player.Player;
import se.webbzon.boltzmann.player.PlayerLocation;

public class GameWriter {
	
	// The bass version
	private static final int version = 1;
	
	/*============================================================
	Public Methods
	============================================================*/
	
	public void write(GameEnvironment env, OutputStream os) throws IOException {
		DataOutputStream dos = new DataOutputStream(os);
		
		dos.write(new byte[] {'B', 'A', 'S', 'S'});
		dos.writeInt(version);
		
		Player firstPlayer = null;
		Collection<Player> players = env.getPlayers();
		dos.writeByte((byte) players.size());
		
		for (Player player : players) {
			if (firstPlayer == null)
				firstPlayer = player;

			Inventory inv = player.getInventory();
			int inventorySize = inv.getColumns() * inv.getRows();
			// Store the character
			dos.writeInt(40 + inventorySize * 4);
			dos.writeInt(CharacterEnum.fromCharacter(player.getCharacter()).ordinal());
			dos.writeInt(player.getHealth().getMaxHealth());
			dos.writeInt(player.getHealth().getHealth());
			dos.writeInt(player.getEnergy().getMaxEnergy());
			dos.writeInt(player.getEnergy().getEnergy());
			dos.writeInt(player.getCoins().getMaxCoins());
			dos.writeInt(player.getCoins().getCoins());
			dos.writeInt(player.getLevel().getLevel());
			dos.writeInt(player.getLevel().getNotes());
			dos.writeInt(inventorySize);
			for (int row = 0; row < inv.getRows(); row++) {
				for (int col = 0; col < inv.getColumns(); col++) {
					AbstractItem item = inv.getItem(row, col);
					if (item == null)
						dos.writeInt(-1);
					else
						dos.writeInt(item.getId());
				}
			}
		}
		
		// Store the location data
		if (firstPlayer == null)
			dos.writeInt(0);
		else {
			PlayerLocation location = firstPlayer.getLocation();
			byte[] wName = location.getWorldAreaName().getBytes("UTF-8");
			dos.writeInt(3 + wName.length);
			dos.writeShort(wName.length);
			dos.write(wName);
			dos.writeByte(location.getPortalId());
		}
		
		// Store the game persistences
		Collection<RegionObject> persistences = env.getGamePersistances();
		int nrOfPersistences = persistences.size();
		int perSize = 8 * nrOfPersistences;
		dos.writeInt(perSize);
		dos.writeInt(nrOfPersistences);
		for (RegionObject obj : persistences)
			dos.writeLong(obj.getId());
		
		// Store the variable map
		ArrayList<VariableEntry<Double>> doubles = env.getVariables().doubles();
		ArrayList<VariableEntry<String>> strings = env.getVariables().strings();
		byte[][] dNames = new byte[doubles.size()][];
		byte[][] sNames = new byte[strings.size()][];
		byte[][] sValues = new byte[strings.size()][];
		int varSize = 10 * doubles.size() + 4 * strings.size();
		// Converts the variable names
		for (int i = 0; i < doubles.size(); i++) {
			byte[] data = doubles.get(i).getName().getBytes("UTF-8");
			dNames[i] = data;
			varSize = data.length;
		}
		for (int i = 0; i < strings.size(); i++) {
			byte[] data = strings.get(i).getName().getBytes("UTF-8");
			sNames[i] = data;
			varSize = data.length;
		}
		// Converts the variable data
		for (int i = 0; i < strings.size(); i++) {
			byte[] data = strings.get(i).getValue().getBytes("UTF-8");
			sValues[i] = data;
			varSize = data.length;
		}
		// Store the data
		dos.writeInt(varSize);
		dos.writeInt(dNames.length);
		for (int i = 0; i < dNames.length; i++) {
			dos.writeShort(dNames[i].length);
			dos.write(dNames[i]);
			dos.writeDouble(doubles.get(i).getValue());
		}
		dos.writeInt(sNames.length);
		for (int i = 0; i < sNames.length; i++) {
			dos.writeShort(sNames[i].length);
			dos.write(sNames[i]);
			dos.writeShort(sValues[i].length);
			dos.write(sValues[i]);
		}
	}

}
